/*
+---------------------------------------------------------------------+
| iThinkphp     | [ WE CAN DO IT JUST THINK ]                         |
+---------------------------------------------------------------------+
| Official site | http://www.ithinkphp.org/                           |
+---------------------------------------------------------------------+
| Author        | hello wf585858@yeah.net                             |
+---------------------------------------------------------------------+
| Repository    | https://gitee.com/wf5858585858/iThinkphp            |
+---------------------------------------------------------------------+
| Licensed      | http://www.apache.org/licenses/LICENSE-2.0 )        |
+---------------------------------------------------------------------+
*/

/*!
 * Cropper v0.3.2
 * https://github.com/fengyuanchen/cropper
 *
 * Copyright 2014 Fengyuan Chen
 * Released under the MIT license
 */

(function (factory) {
	if (typeof define === "function" && define.amd)
	{
		// AMD. Register as anonymous module.
		define(["jquery"], factory);
	}
	else
	{
		// Browser globals.
		factory(jQuery);
	}
}(function ($) {

	"use strict";

	var $window = $(window),
		Cropper = function (element, options) {
			options = $.isPlainObject(options) ? options : {};
			this.$image = $(element);
			this.defaults = $.extend({}, Cropper.defaults, this.$image.data(), options);
			this.init();
		};

	Cropper.prototype = {
		construstor: Cropper,

		init: function () {
			this.setAspectRatio(this.defaults.aspectRatio);
			this.render();
		},

		render: function (callback) {
			var that = this,
				$image = this.$image,
				$clone,
				src;

			if (this.active)
			{
				return;
			}

			if (this.$clone)
			{
				this.$clone.remove(); // Remove the old clone
			}

			src = $image.attr("src"); // Don't use "prop"
			$clone = $('<img src="' + src + '">');

			$clone.on("load", function () {
				var image;

				$clone.off("load");

				if (this.naturalWidth && this.naturalHeight)
				{
					image = {
						naturalHeight: this.naturalHeight,
						naturalWidth : this.naturalWidth
					};
				}
				else
				{
					Cropper.fn.size($clone, {
						height: "auto",
						width : "auto"
					});

					image = Cropper.fn.size($clone);
					image = {
						naturalHeight: image.height,
						naturalWidth : image.width
					};
				}

				Cropper.fn.size($clone, {
					height: "100%",
					width : "100%"
				});

				image.aspectRatio = image.naturalWidth / image.naturalHeight;
				that.src = src;
				that.image = image;
				that.active = true;
				that.createCropper();
			});

			if ($.isFunction(callback))
			{
				$image.on("ready.cropper", callback);
			}

			this.$clone = $clone;
			$image.after($clone);
		},

		unrender: function () {
			if (this.active)
			{
				this.active = false;
				this.removeCropper();
				this.src = "";
				this.image = null;
				this.cropper = null;
				this.dragger = null;
			}
		},

		rerender: function () {
			this.unrender();
			this.render();
		},

		resize: function () {
			clearTimeout(this.resizing);
			this.resizing = setTimeout($.proxy(this.rerender, this), 200);
		},

		createCropper: function () {
			this.$cropper = $(Cropper.template);
			this.$dragger = this.$cropper.find(".cropper-dragger");
			Cropper.fn.toggle(this.$image);
			this.$image.after(this.$cropper);
			this.$cropper.prepend(this.$clone);

			if (!this.defaults.modal)
			{
				Cropper.fn.toggle(this.$cropper.find(".cropper-modal"));
			}

			this.setPreview();
			this.addListener();
		},

		removeCropper: function () {
			this.removeListener();
			this.$preview = null;
			this.$clone.remove();
			this.$clone = null;
			this.$dragger = null;
			this.$cropper.remove();
			this.$cropper = null;
			Cropper.fn.toggle(this.$image);
		},

		addListener: function () {
			this.$cropper.bind("mousedown touchstart", $.proxy(this.dragstart, this));
			this.$cropper.bind("mousemove touchmove", $.proxy(this.dragmove, this));
			this.$cropper.bind("mouseup mouseleave touchend touchleave", $.proxy(this.dragend, this));
			$window.on("resize", $.proxy(this.resize, this));
		},

		removeListener: function () {
			this.$cropper.unbind("mousedown touchstart", this.dragstart);
			this.$cropper.unbind("mousemove touchmove", this.dragmove);
			this.$cropper.unbind("mouseup mouseleave touchend touchleave", this.dragend);
			$window.off("resize", this.resize);
		},

		setPreview: function () {
			var preview = this.defaults.preview;

			this.$preview = this.$cropper.find(".cropper-preview");

			if (typeof preview === "string" && preview.length > 0)
			{
				this.$preview = this.$preview.add(preview);
			}

			this.$preview.html('<img src="' + this.src + '">');
			this.setCropper();
		},

		setCropper: function () {
			var $container = this.$image.parent(),
				container = Cropper.fn.size($container),
				image = this.image,
				cropper;

			if (((image.naturalWidth * container.height / image.naturalHeight) - container.width) >= 0)
			{
				cropper = {
					height: container.width / image.aspectRatio,
					width : container.width,
					left  : 0
				};

				cropper.top = (container.height - cropper.height) / 2;
			}
			else
			{
				cropper = {
					height: container.height,
					width : container.height * image.aspectRatio,
					top   : 0
				};

				cropper.left = (container.width - cropper.width) / 2;
			}

			$.each(cropper, function (i, n) {
				cropper[i] = Math.round(n);
			});

			image.height = cropper.height;
			image.width = cropper.width;
			image.ratio = image.width / image.naturalWidth;

			Cropper.fn.position($container);
			this.$cropper.css({
				height: cropper.height,
				left  : cropper.left,
				top   : cropper.top,
				width : cropper.width
			});

			this.cropper = cropper;
			this.setDragger();
		},

		setDragger: function () {
			var cropper = this.cropper,
				// If not set, use the original aspect ratio of the image.
				aspectRatio = this.defaults.aspectRatio || this.image.aspectRatio,
				dragger;

			if (((cropper.height * aspectRatio) - cropper.width) >= 0)
			{
				dragger = {
					height   : cropper.width / aspectRatio,
					width    : cropper.width,
					left     : 0,
					top      : (cropper.height - (cropper.width / aspectRatio)) / 2,
					maxWidth : cropper.width,
					maxHeight: cropper.width / aspectRatio
				};
			}
			else
			{
				dragger = {
					height   : cropper.height,
					width    : cropper.height * aspectRatio,
					left     : (cropper.width - (cropper.height * aspectRatio)) / 2,
					top      : 0,
					maxHeight: cropper.height,
					maxWidth : cropper.height * aspectRatio
				};
			}

			dragger.height *= 0.8;
			dragger.width *= 0.8;

			dragger.left = (cropper.width - dragger.width) / 2;
			dragger.top = (cropper.height - dragger.height) / 2;

			this.dragger = Cropper.fn.round(dragger);
			this.setData(this.defaults.data);
			this.$image.trigger("ready.cropper").off("ready.cropper");
		},

		resetDragger: function () {
			var dragger = this.dragger,
				cropper = this.cropper;

			dragger.width = dragger.width > dragger.maxWidth ? dragger.maxWidth : Math.abs(dragger.width);
			dragger.height = dragger.height > dragger.maxHeight ? dragger.maxHeight : Math.abs(dragger.height);

			dragger.maxLeft = cropper.width - dragger.width;
			dragger.maxTop = cropper.height - dragger.height;

			dragger.left = dragger.left < 0 ? 0 : dragger.left > dragger.maxLeft ? dragger.maxLeft : dragger.left;
			dragger.top = dragger.top < 0 ? 0 : dragger.top > dragger.maxTop ? dragger.maxTop : dragger.top;

			dragger = Cropper.fn.round(dragger);

			this.$dragger.css({
				height: dragger.height,
				left  : dragger.left,
				top   : dragger.top,
				width : dragger.width
			});

			this.dragger = dragger;
			this.preview();
			this.output();
		},

		dragging: function () {
			var direction = this.direction,
				dragger = this.dragger,
				aspectRatio = this.defaults.aspectRatio,
				range = {
					x: this.endX - this.startX,
					y: this.endY - this.startY
				};

			if (aspectRatio)
			{
				range.X = range.y * aspectRatio;
				range.Y = range.x / aspectRatio;
			}

			switch (direction)
			{

				// dragging
				case "e":
					dragger.width += range.x;

					if (aspectRatio)
					{
						dragger.height = dragger.width / aspectRatio;
						dragger.top -= range.Y / 2;
					}

					if (dragger.width < 0)
					{
						this.direction = "w";
						dragger.width = 0;
					}

					break;

				case "n":
					dragger.height -= range.y;
					dragger.top += range.y;

					if (aspectRatio)
					{
						dragger.width = dragger.height * aspectRatio;
						dragger.left += range.X / 2;
					}

					if (dragger.height < 0)
					{
						this.direction = "s";
						dragger.height = 0;
					}

					break;

				case "w":
					dragger.width -= range.x;
					dragger.left += range.x;

					if (aspectRatio)
					{
						dragger.height = dragger.width / aspectRatio;
						dragger.top += range.Y / 2;
					}

					if (dragger.width < 0)
					{
						this.direction = "e";
						dragger.width = 0;
					}

					break;

				case "s":
					dragger.height += range.y;

					if (aspectRatio)
					{
						dragger.width = dragger.height * aspectRatio;
						dragger.left -= range.X / 2;
					}

					if (dragger.height < 0)
					{
						this.direction = "n";
						dragger.height = 0;
					}

					break;

				case "ne":
					dragger.height -= range.y;
					dragger.top += range.y;

					if (aspectRatio)
					{
						dragger.width = dragger.height * aspectRatio;
					}
					else
					{
						dragger.width += range.x;
					}

					if (dragger.height < 0)
					{
						this.direction = "sw";
						dragger.height = 0;
						dragger.width = 0;
					}

					break;

				case "nw":
					dragger.height -= range.y;
					dragger.top += range.y;

					if (aspectRatio)
					{
						dragger.width = dragger.height * aspectRatio;
						dragger.left += range.X;
					}
					else
					{
						dragger.width -= range.x;
						dragger.left += range.x;
					}

					if (dragger.height < 0)
					{
						this.direction = "se";
						dragger.height = 0;
						dragger.width = 0;
					}

					break;

				case "sw":
					dragger.width -= range.x;
					dragger.left += range.x;

					if (aspectRatio)
					{
						dragger.height = dragger.width / aspectRatio;
					}
					else
					{
						dragger.height += range.y;
					}

					if (dragger.width < 0)
					{
						this.direction = "ne";
						dragger.height = 0;
						dragger.width = 0;
					}

					break;

				case "se":
					dragger.width += range.x;

					if (aspectRatio)
					{
						dragger.height = dragger.width / aspectRatio;
					}
					else
					{
						dragger.height += range.y;
					}

					if (dragger.width < 0)
					{
						this.direction = "nw";
						dragger.height = 0;
						dragger.width = 0;
					}

					break;

				// moving
				default:
					dragger.left += range.x;
					dragger.top += range.y;
			}

			this.resetDragger();
			this.startX = this.endX;
			this.startY = this.endY;
		},

		output: function () {
			this.defaults.done(this.getData());
		},

		preview: function () {
			var that = this,
				cropper = that.cropper,
				dragger = that.dragger;

			this.$preview.each(function () {
				var $this = $(this),
					ratio = $this.outerWidth() / dragger.width,
					styles = {
						height    : cropper.height,
						marginLeft: -dragger.left,
						marginTop : -dragger.top,
						width     : cropper.width
					};

				$this.css({overflow: "hidden"});
				$this.find("img").css(Cropper.fn.round(styles, function (n) {
					return n * ratio;
				}));
			});
		},

		// Public methods

		enable: function (callback) {
			this.render(callback);
		},

		disable: function () {
			this.unrender();
		},

		setAspectRatio: function (aspectRatio) {
			if (aspectRatio === "auto" || ($.isNumeric(aspectRatio) && aspectRatio > 0))
			{
				this.defaults.aspectRatio = aspectRatio === "auto" ? NaN : aspectRatio;

				if (this.active)
				{
					this.setDragger();
				}
			}
		},

		setData: function (data) {
			var cropper = this.cropper,
				dragger = this.dragger,
				aspectRatio = this.defaults.aspectRatio,
				isNumber = function (n) {
					return typeof n === "number";
				};

			if (!this.active)
			{
				return;
			}

			if ($.isPlainObject(data) && !$.isEmptyObject(data))
			{
				data = Cropper.fn.transformData(data, this.image.ratio);

				if (isNumber(data.x1) && data.x1 <= cropper.width)
				{
					dragger.left = data.x1;
				}

				if (isNumber(data.y1) && data.y1 <= cropper.height)
				{
					dragger.top = data.y1;
				}

				if (aspectRatio)
				{
					if (isNumber(data.width) && data.width <= cropper.width)
					{
						dragger.width = data.width;
						dragger.height = dragger.width / aspectRatio;
					}
					else if (isNumber(data.height) && data.height <= cropper.height)
					{
						dragger.height = data.height;
						dragger.width = dragger.height * aspectRatio;
					}
					else if (isNumber(data.x2) && data.x2 <= cropper.width)
					{
						dragger.width = data.x2 - dragger.left;
						dragger.height = dragger.width / aspectRatio;
					}
					else if (isNumber(data.y2) && data.y2 <= cropper.height)
					{
						dragger.height = data.y2 - dragger.top;
						dragger.width = dragger.height * aspectRatio;
					}
				}
				else
				{
					if (isNumber(data.width) && data.width <= cropper.width)
					{
						dragger.width = data.width;
					}
					else if (isNumber(data.x2) && data.x2 <= cropper.width)
					{
						dragger.width = data.x2 - dragger.left;
					}

					if (isNumber(data.height) && data.height <= cropper.height)
					{
						dragger.height = data.height;
					}
					else if (isNumber(data.y2) && data.height <= cropper.height)
					{
						dragger.height = data.y2 - dragger.top;
					}
				}
			}

			this.dragger = dragger;
			this.resetDragger();
		},

		getData: function () {
			var dragger = this.dragger,
				data = {};

			if (this.active)
			{
				data = {
					x1    : dragger.left,
					y1    : dragger.top,
					width : dragger.width,
					height: dragger.height,
					x2    : dragger.left + dragger.width,
					y2    : dragger.top + dragger.height
				};

				data = Cropper.fn.transformData(data, (1 / this.image.ratio));
			}

			return data;
		},

		setImgSrc: function (src) {
			if (typeof src === "string" && src.length > 0 && src !== this.src)
			{
				this.$image.attr("src", src);
				this.rerender();
			}
		},

		getImgInfo: function () {
			return this.image || {};
		},

		// Public events

		dragstart: function (event) {
			var touches = Cropper.fn.getOriginalEvent(event).touches,
				e = event,
				touching,
				direction;

			if (touches && touches.length === 1)
			{
				e = touches[0];
				this.touchId = e.identifier;
				touching = true;
			}

			direction = $(e.target).data().direction;

			if (Cropper.fn.isDirection(direction))
			{
				this.startX = e.pageX;
				this.startY = e.pageY;
				this.direction = direction;
				this.$image.trigger("dragstart");
				touching && event.preventDefault();
			}
		},

		dragmove: function (event) {
			var touches = Cropper.fn.getOriginalEvent(event).changedTouches,
				e = event,
				touching;

			if (touches && touches.length === 1)
			{
				e = touches[0];
				touching = true;

				if (e.identifier !== this.touchId)
				{
					return;
				}
			}

			if (this.direction)
			{
				this.$image.trigger("dragmove");
				touching && event.preventDefault();
				this.endX = e.pageX;
				this.endY = e.pageY;
				this.dragging();
			}
		},

		dragend: function (event) {
			var touches = Cropper.fn.getOriginalEvent(event).changedTouches,
				e = event,
				touching;

			if (touches && touches.length === 1)
			{
				e = touches[0];
				touching = true;

				if (e.identifier !== this.touchId)
				{
					return;
				}
			}

			if (this.direction)
			{
				this.direction = "";
				this.$image.trigger("dragend");
				touching && event.preventDefault();
			}
		}
	};

	// Common methods
	Cropper.fn = {
		toggle: function ($e) {
			$e.toggleClass("cropper-hidden");
		},

		position: function ($e, option) {
			var position = $e.css("position");

			if (position === "static")
			{
				$e.css("position", option || "relative");
			}
		},

		size: function ($e, options) {
			if ($.isPlainObject(options))
			{
				$e.css(options);
			}
			else
			{
				return {
					height: $e.height(),
					width : $e.width()
				};
			}
		},

		round: function (data, fn) {
			var value,
				i;

			for (i in data)
			{
				value = data[i];

				if (data.hasOwnProperty(i) && typeof value === "number")
				{
					data[i] = Math.round($.isFunction(fn) ? fn(value) : value);
				}
			}

			return data;
		},

		transformData: function (data, ratio) {
			var that = this,
				result = {};

			$.each(data, function (i, n) {
				if (that.isDataOption(i) && $.isNumeric(n) && n >= 0)
				{
					result[i] = Math.round(n * ratio);
				}
			});

			return result;
		},

		getOriginalEvent: function (event) {
			if (event && typeof event.originalEvent !== "undefined")
			{
				event = event.originalEvent;
			}

			return event;
		},

		isDataOption: function (s) {
			return /^(x1|y1|x2|y2|width|height)$/i.test(s);
		},

		isDirection: function (s) {
			return /^(\*|e|n|w|s|ne|nw|sw|se)$/i.test(s);
		}
	};

	Cropper.template = [
		'<div class="cropper-container">',
		'<div class="cropper-modal"></div>',
		'<div class="cropper-dragger">',
		'<span class="cropper-preview"></span>',
		'<span class="cropper-dashed dashed-h"></span>',
		'<span class="cropper-dashed dashed-v"></span>',
		'<span class="cropper-face" data-direction="*"></span>',
		'<span class="cropper-line line-e" data-direction="e"></span>',
		'<span class="cropper-line line-n" data-direction="n"></span>',
		'<span class="cropper-line line-w" data-direction="w"></span>',
		'<span class="cropper-line line-s" data-direction="s"></span>',
		'<span class="cropper-point point-e" data-direction="e"></span>',
		'<span class="cropper-point point-n" data-direction="n"></span>',
		'<span class="cropper-point point-w" data-direction="w"></span>',
		'<span class="cropper-point point-s" data-direction="s"></span>',
		'<span class="cropper-point point-ne" data-direction="ne"></span>',
		'<span class="cropper-point point-nw" data-direction="nw"></span>',
		'<span class="cropper-point point-sw" data-direction="sw"></span>',
		'<span class="cropper-point point-se" data-direction="se"></span>',
		'</div>',
		'</div>'
	].join("");

	Cropper.defaults = {
		aspectRatio: "auto",
		data       : {},
		done       : function (/* data */) {},
		modal      : true,
		preview    : ""
	};

	Cropper.setDefaults = function (options) {
		$.extend(Cropper.defaults, options);
	};

	// Register as jQuery plugin
	$.fn.cropper = function (options, settings) {
		var result = this;

		this.each(function () {
			var $this = $(this),
				data = $this.data("cropper");

			if (!data)
			{
				data = new Cropper(this, options);
				$this.data("cropper", data);
			}

			if (typeof options === "string" && $.isFunction(data[options]))
			{
				result = data[options](settings);
			}
		});

		return (typeof result !== "undefined" ? result : this);
	};

	$.fn.cropper.Constructor = Cropper;
	$.fn.cropper.setDefaults = Cropper.setDefaults;

	$(function () {
		$("img[cropper]").cropper();
	});
}));
